<?php
/**
 * Groo metadata fetch code for Amazon.com.
 *
 * $Horde: incubator/groo/lib/Fetch/Amazon.php,v 1.6 2006/08/13 21:04:28 luciano Exp $
 *
 * Copyright 2004-2006 Luciano Ramalho <luciano@ramalho.org>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Luciano Ramalho <luciano@ramalho.org>
 * @package Groo
 */

error_reporting(E_ALL); assert_options(ASSERT_ACTIVE,1);
assert_options(ASSERT_WARNING,1); assert_options(ASSERT_BAIL,1);

//FIXME: ugly hack to read Groo conf from a CLI script
require '../../groo/config/conf.php';

// change this to your Amazon.com ECS Access Key... 
define('ACCESS_KEY', $conf['fetch']['amazon_access_key']);
// leave this Associate ID or provide your own
define('ASSOCIATE_TAG', $conf['fetch']['amazon_associate_tag']);
// this should not change
define('BASE_URL','http://webservices.amazon.com/onca/xml?Service=AWSECommerceService');
// for post-mortem debugging
define('SAVE_XML',true);




/********** XML parsing ************/

class AmazonException extends FetchException { };

function arrayUnique($myArray)
{
    /* this does what the half-baked array_unique PHP function should do;
       adapted from a post from mcmeijer at yahoo dot com in:
       http://www.php.net/manual/en/function.array-unique.php
    */
    $newArray = Array();
    foreach($myArray as $key=>$val) {
        if (is_array($val)) {
            $val2 = arrayUnique($val);
        } else {
            $val2 = $val;
            $newArray=array_unique($myArray);
            break;
        }
        if (!empty($val2)) {
            $newArray[$key] = $val2;
        }
    }
    return $newArray;
}

function parseItemAttributes(DOMDocument $doc)
{
    /* extract metadata from Amazon.com ECS ItemAttributes Response Group
      return an array suitable for Book constructor
    */
    
    $metadata =array();
    
    $singleFields = array(
        'title'     => array('Title',1), # Tag name, required
        'isbn'      => array('ISBN',0),
        'edition'   => array('Edition',0),
        'publisher' => array('Publisher',0),
        'issued' => array('PublicationDate',0)
    );
    
    foreach ($singleFields as $fieldName=>$properties) {
        list($tag, $required) = $properties;
        $metadata[$fieldName] = removeExtraSpaces(
            getSingleElementValue($doc, $tag, $required));
       
    }
    
    $creators = array();
    $items = $doc->getElementsByTagName('Author');
    foreach ($items as $item) {
        $creators[] = array('name'=>removeExtraSpaces($item->nodeValue),
                           'role'=>'author');
    }
    
    $items = $doc->getElementsByTagName('Creator');
    foreach ($items as $item) {
        $role = mb_strtolower($item->getAttribute('Role'));
        $creators[] = array('name'=>removeExtraSpaces($item->nodeValue),
                            'role'=>$role);
    }
    $creators = arrayUnique($creators);

    if (count($creators)) {
        $metadata['creators'] = $creators;
    }
    return $metadata;
};

function parseImage(DOMDocument $doc)
{
    /* extract metadata from Amazon.com ECS Images Response Group
      return a the first LargeImage URL
    */
    
    $imgNodes = $doc->getElementsByTagName('LargeImage');
    if ($imgNodes->item(0)) {
        return getSingleElementValue($imgNodes->item(0),'URL',true);
    } else {
        return NULL;
    }
};


function getErrors(SimpleXMLElement $xml) {
    $errors = array();
    foreach ($xml->Error as $error) {
        $errors[] = array('code'=>(string)$error->Code,
                          'msg'=>(string)$error->Message);    
    }
    return $errors;
}

/********** Fetch response ************/
function fetchResponseISBN($isbn, $responseGroup, $save_xml=0, $delay=1) {
    // Amazon.com ECS agreement imposes a limit of one request per second
    sleep($delay);
    $url = BASE_URL.
        '&AWSAccessKeyId='.ACCESS_KEY.
        '&AssociateTag='.ASSOCIATE_TAG.
        '&Operation=ItemLookup'.
        '&ResponseGroup='.$responseGroup.
        '&ItemId='; // here goes the isbn;
    $ch = curl_init($url.$isbn);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    $xml = curl_exec($ch);
    if ($error=curl_error($ch) ) {
        // Couldn't resolve host etc...
        throw new FetchNetworkException("cURL: $error");
    } elseif ('200'!=($http_code=curl_getinfo($ch, CURLINFO_HTTP_CODE))) {
        throw new AmazonException("cURL: Unexpected HTTP code ($http_code)");
    }
    curl_close($ch);
    if ($save_xml) {
        $path = "Fetch/amazon_xml/$responseGroup/$isbn.xml";
        $fp = fopen($path, 'w');
        if ($fp) {
            fwrite($fp, $xml);
            fclose($fp);
        } else {
            error_log(__FILE__.":fetchResponseISBN: Unable to write to local path '$path'");
        } 
    }
    return $xml;
}

function fetchISBN($isbn) {
    $xml = fetchResponseISBN($isbn, 'ItemAttributes', true);
    $doc = new DOMDocument();
    $doc->loadXML($xml);
    if ($errors = getSingleElementValue($doc, 'Errors')) {
        $code = getSingleElementValue($doc, 'Code');
        $message = getSingleElementValue($doc, 'Message');
        throw new AmazonException("$code: $message");
    }
    return parseItemAttributes($doc);
}

function fetchISBNimageURL($isbn) {
    $xml = fetchResponseISBN($isbn, 'Images', true);
    $doc = new DOMDocument();
    $doc->loadXML($xml);
    if ($errors = getSingleElementValue($doc, 'Errors')) {
        $code = getSingleElementValue($doc, 'Code');
        $message = getSingleElementValue($doc, 'Message');
        throw new AmazonException("$code: $message");
    }
    return parseImage($doc);
}

function fetchISBNimage($isbn) {
    $url = fetchISBNimageURL($isbn);
    if (is_null($url)) {
        throw new AmazonException('fetchISBNimage:no image found for '.$isbn);
    }
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
    $img = curl_exec($ch);
    if ($error=curl_error($ch) ) {
        // Couldn't resolve host etc...
        throw new FetchNetworkException("cURL: $error");
    } elseif ('200'!=($http_code=curl_getinfo($ch, CURLINFO_HTTP_CODE))) {
        throw new AmazonException("fetchISBNimage:cURL: Unexpected HTTP code ($http_code)");
    }
    curl_close($ch);
    return $img; // return binary image
}


/*** self test ***/
if (php_sapi_name()=='cli' and $argc==3 and $argv[1]=='--fetchResponseISBN') {
    require_once('ISBN.php');
    $isbn = $argv[2];
    if (ISBN::isValidISBN10($isbn)) {
        echo "Fetching $isbn...\n";
        $response = fetchResponseISBN($isbn, true);
        var_dump($response);
    } else {
        echo "Invalid ISBN-10\n";
    }
}


/* NOTE: 0333647289 is a valid ISBN which generates a AWS.InvalidParameterValue
    from Amazon.com with message: "0333647289 is not a valid value for ItemId"
    The book is Virtual History: Alternatives and Counterfactuals
    by Niall Ferguson (Editor)
    Amazon.com does not have it but Amazon.co.uk does and
    Google query "isbn 0333647289" also found it here:
    http://www.alibris.com/search/search.cfm?qwork=7055972
*/  
?>